package org.aplikator.client.local.widgets;
import java.util.Date;
import org.aplikator.client.local.Aplikator;
import org.aplikator.client.shared.data.PrimaryKey;
import org.aplikator.client.shared.descriptor.PropertyDTO;
import org.gwtbootstrap3.client.ui.*;
import org.gwtbootstrap3.client.ui.base.form.AbstractForm;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.FormElement;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Node;
import com.google.gwt.xml.client.XMLParser;
public class BinaryFieldWidget extends Composite implements DataField<String> {
public static final String BUTTON_WIDTH = "90px";
public static final String ENTITY_ID = "entityId";
public static final String PROPERTY_ID = "propertyId";
public static final String PRIMARY_KEY_ID = "primaryKey";
public static final String MAXSIZE_ID = "maxSize";
public static final String ATTACHMENT_ID = "attachment";
public static final String ERROR_PREFIX = "XXXERRORXXX";
public static final int FULL_SIZE_ATTACHMENT_CODE = 0;
public static final int THUMBNAIL_SIZE_CODE = -1;
public static final int PREVIEW_SIZE_CODE = -2;
public static final int FULL_SIZE_IMAGE_CODE = -3;
private static BinaryFieldWidgetUiBinder uiBinder = GWT.create(BinaryFieldWidgetUiBinder.class);
@UiField
Column wrapper;
@UiField
FormLabel label;
@UiField
NavbarText labelHolder;
@UiField
Button buttonUpload;
@UiField
AnchorButton buttonDownload;
@UiField
DeckPanel thumbnailHolder;
@UiField
Image thumbnail;
FormControlStatic primaryKeyField;
private FileUpload upload;
private ProgressTimer timer;
private HTML statusLabel = new HTML(" ");
private boolean uploading = false;
private Modal uploadDialog;
private String entityId;
private PropertyDTO property;
private PrimaryKey primaryKey;
private String tempFileId;
private boolean dirty = false;
private boolean useThumbnail = true;
private boolean enabled = true;
public BinaryFieldWidget(PropertyDTO property, String localizedName, String entityId, int size, boolean enabled, int height, boolean useThumbnail) {
super();
this.property = property;
this.entityId = entityId;
this.useThumbnail = useThumbnail;
this.enabled = enabled;
initWidget(uiBinder.createAndBindUi(this));
this.label.setText(localizedName);
if (localizedName == null || "".equals(localizedName)) {
labelHolder.addStyleName("app-clean-mg-right");
}
setGridSize(size);
thumbnail.addLoadHandler(new LoadHandler() {
@Override
public void onLoad(LoadEvent event) {
thumbnailHolder.showWidget(0);
buttonDownload.setEnabled(true);
//Window.alert("ONLOAD:" + event.toDebugString());
}
});
thumbnail.addErrorHandler(new ErrorHandler() {
@Override
public void onError(ErrorEvent event) {
thumbnailHolder.showWidget(3);
buttonDownload.setEnabled(false);
}
});
thumbnailHolder.add(new HTML(Aplikator.application.getConfigString("aplikator.binary.loading")));
thumbnailHolder.add(new HTML(Aplikator.application.getConfigString("aplikator.binary.uploaded")));
thumbnailHolder.add(new HTML(Aplikator.application.getConfigString("aplikator.binary.notAvailable")));
thumbnailHolder.showWidget(1);
thumbnailHolder.getElement().getStyle().setProperty("width", "100%");
if (height > 0) {
thumbnailHolder.getElement().getStyle().setHeight(height, Style.Unit.PX);
}
thumbnailHolder.getElement().getStyle().setDisplay(Style.Display.INLINE_BLOCK);
LayoutUtils.addTooltip(buttonUpload, Aplikator.application.getConfigString("aplikator.binary.upload"));
thumbnail.getElement().getStyle().setProperty("maxWidth", "100%");
thumbnail.getElement().getStyle().setProperty("maxHeight", "100%");
thumbnail.getElement().getStyle().clearWidth();
thumbnail.getElement().getStyle().clearHeight();
enableUpload();
LayoutUtils.addTooltip(buttonDownload, Aplikator.application.getConfigString("aplikator.binary.download"));
buttonDownload.setEnabled(false);
/*thumbnail.addDropHandler(new DropHandler() {
@Override
public void onDrop(DropEvent event) {
event.preventDefault();
// not sure if the calculation is right, didn't test it really
int x = (event.getNativeEvent().getClientX() - thumbnail.getAbsoluteLeft()) + Window.getScrollLeft();
int y = (event.getNativeEvent().getClientY() - thumbnail.getAbsoluteTop()) + Window.getScrollTop();
thumbnail.getElement().getStyle().clearBackgroundColor();
Window.alert("x: " + x + ", y:" + y);
// add image with same URL as the dropped one to absolute panel at given coordinates
//thumbnail.add(new Image(event.getData("text")), x, y);
}
});*/
wrapper.addDomHandler(new DragEnterHandler() {
@Override
public void onDragEnter(DragEnterEvent event) {
}
}, DragEnterEvent.getType());
wrapper.addDomHandler(new DragLeaveHandler() {
@Override
public void onDragLeave(DragLeaveEvent event) {
highlight(false);
}
}, DragLeaveEvent.getType());
wrapper.addDomHandler(new DragOverHandler() {
@Override
public void onDragOver(DragOverEvent event) {
highlight(true);
}
}, DragOverEvent.getType());
wrapper.addDomHandler(new DropHandler() {
@Override
public void onDrop(DropEvent event) {
// stop default behaviour
event.preventDefault();
event.stopPropagation();
// starts the fetching, reading and callbacks
//handleFiles(event.getDataTransfer());
highlight(false);
Window.alert("DROPPED" + event.getDataTransfer().getData("image/jpeg"));
}
}, DropEvent.getType());
}
private void highlight(boolean on) {
if (on) {
wrapper.getElement().getStyle().setBorderWidth(10, Style.Unit.PX);
} else {
wrapper.getElement().getStyle().setBorderWidth(0, Style.Unit.PX);
}
}
protected void setGridSize(int size) {
wrapper.setSize(LayoutUtils.size(size));
}
private Modal createDialogBox() {
// Create a FormPanel and point it at a service.
final Form form = new Form();
form.setAction(Aplikator.getBaseURL() + "upload");
// Because we're going to add a FileUpload widget, we'll need to set the
// form to use the POST method, and multipart MIME encoding.
form.setEncoding(FormPanel.ENCODING_MULTIPART);
form.setMethod(FormPanel.METHOD_POST);
FormElement.as(form.getElement()).setAcceptCharset("UTF-8");
// Create a panel to hold all of the form widgets.
FieldSet panel = new FieldSet();
form.add(panel);
// add hidden upload parameters
FormControlStatic entityIdField = new FormControlStatic();
entityIdField.setId(ENTITY_ID);
entityIdField.setText(this.entityId);
entityIdField.setVisible(false);
FormControlStatic propertyIdField = new FormControlStatic();
propertyIdField.setId(PROPERTY_ID);
propertyIdField.setText(property.getId());
propertyIdField.setVisible(false);
primaryKeyField = new FormControlStatic();
primaryKeyField.setId(PRIMARY_KEY_ID);
primaryKeyField.setVisible(false);
FormGroup entityIdFG = new FormGroup();
entityIdFG.add(entityIdField);
FormGroup propertyIdFG = new FormGroup();
propertyIdFG.add(propertyIdField);
FormGroup primaryKeyFG = new FormGroup();
primaryKeyFG.add(primaryKeyField);
panel.add(entityIdFG);
panel.add(propertyIdFG);
panel.add(primaryKeyFG);
// Create a FileUpload widget.
upload = new OnChangeFileUpload(form);
upload.setName("uploadFormElement");
panel.add(upload);
panel.add(statusLabel);
timer = new ProgressTimer(statusLabel);
timer.scheduleRepeating(1000);
final Modal db = new Modal();
db.getElement().getStyle().setOverflowY(Style.Overflow.AUTO);//fix against hidding scrollbar in modal stack
ModalBody contents = new ModalBody();
db.setClosable(true);
db.setSize(ModalSize.SMALL);
db.setTitle(Aplikator.application.getConfigString("aplikator.binary.uploadTitle"));
db.add(contents);
db.setFade(true);
contents.add(form);
// Add an event handler to the form.
form.addSubmitCompleteHandler(new AbstractForm.SubmitCompleteHandler() {
@Override
public void onSubmitComplete(AbstractForm.SubmitCompleteEvent event) {
timer.setRunning(false);
uploading = false;
String uploadedFilename = "";
Document d = XMLParser.parse(event.getResults());
Node de = d.getDocumentElement();
if (de != null && de.getFirstChild() != null) {
uploadedFilename = de.getFirstChild().getNodeValue();
}
if ("".equals(uploadedFilename)) {
statusLabel.setHTML(Aplikator.application.getConfigString("aplikator.binary.statusUploadFailed"));
} else if (uploadedFilename.startsWith(ERROR_PREFIX)) {
statusLabel.setHTML(Aplikator.application.getConfigString("aplikator.binary.statusUploadFailed")
+ ": " + uploadedFilename.replace(ERROR_PREFIX, ""));
} else {
statusLabel.setHTML(Aplikator.application.getConfigString("aplikator.binary.statusUploaded"));
setValue(uploadedFilename);
setDirty(true);
thumbnailHolder.showWidget(2);
//Window.alert("COMPLETE");
new Timer() {
public void run() {
db.hide();
}
}.schedule(1500);
}
}
});
form.addSubmitHandler(new AbstractForm.SubmitHandler() {
@Override
public void onSubmit(AbstractForm.SubmitEvent event) {
uploading = true;
timer.setRunning(true);
// start the timer that monitors the progress
new Timer() {
public void run() {
if (uploading) {
timer.run();
}
}
}.schedule(2000);
primaryKeyField.setText(Integer.toString(primaryKey.getId()));
statusLabel.setText(Aplikator.application.getConfigString("aplikator.binary.statusStarted"));
//Window.alert("SUBMITTED");
}
});
return db;
}
@UiHandler("buttonUpload")
void buttonUploadClicked(ClickEvent e) {
if (uploadDialog == null) {
uploadDialog = createDialogBox();
}
resetUpload();
uploadDialog.show();
}
private void resetUpload() {
statusLabel.setText("");
timer.reset();
upload.getElement().setPropertyString("value", "");
}
@UiHandler("buttonDownload")
void buttonDownloadClicked(ClickEvent e) {
Window.open(getDownloadUrl(FULL_SIZE_ATTACHMENT_CODE), "_self", "");
}
public void setPrimaryKey(PrimaryKey primaryKey) {
this.primaryKey = primaryKey;
this.tempFileId = null;
enableUpload();
buttonDownload.setEnabled(false);
thumbnailHolder.showWidget(1);
if (primaryKey.getId() > 0) {
thumbnail.setUrl(getDownloadUrl(useThumbnail ? THUMBNAIL_SIZE_CODE : PREVIEW_SIZE_CODE));
buttonDownload.setHref(getDownloadUrl(FULL_SIZE_ATTACHMENT_CODE));
} else {
thumbnailHolder.showWidget(3);
}
}
private String getDownloadUrl(int maxSize) {
StringBuilder url = new StringBuilder(Aplikator.getBaseURL() + "download?");
url.append(ENTITY_ID + "=" + entityId + "&");
url.append(PROPERTY_ID + "=" + property.getId() + "&");
url.append(PRIMARY_KEY_ID + "=" + primaryKey.getId() + "&");
url.append(MAXSIZE_ID + "=" + maxSize + "&");
url.append("timestamp" + "=" + (new Date()).getTime());
return url.toString();
}
private void enableUpload() {
buttonUpload.setEnabled(enabled);
}
@UiHandler("thumbnail")
void showLargePreview(ClickEvent e) {
final Modal dialogBox = new Modal();
dialogBox.getElement().getStyle().setOverflowY(Style.Overflow.AUTO);//fix against hidding scrollbar in modal stack
dialogBox.setSize(ModalSize.LARGE);
//dialogBox.setDataBackdrop(ModalBackdrop.STATIC);
dialogBox.setRemoveOnHide(true);
ModalBody contents = new ModalBody();
Image image = new Image(getDownloadUrl(PREVIEW_SIZE_CODE));
image.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
dialogBox.hide();
}
});
ScrollPanel imageScroller = new ScrollPanel(image);
dialogBox.add(contents);
contents.add(imageScroller);
dialogBox.setFade(true);
dialogBox.show();
}
@Override
public PropertyDTO getProperty() {
return property;
}
@Override
public String getValue() {
return tempFileId;
}
@Override
public void setValue(String value) {
tempFileId = value;
ValueChangeEvent.fire(this, value);
}
@Override
public boolean isDirty() {
return dirty;
}
@Override
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
@Override
public void setEnabled(boolean enabled) {
if (property.getRefferedThrough() != null) {
enabled = false;
}
this.enabled = enabled;
enableUpload();
}
@Override
public void grabFocus() {
}
@Override
public void addEnterHandler(Command command) {
}
@Override
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
return this.addHandler(handler, ValueChangeEvent.getType());
}
interface BinaryFieldWidgetUiBinder extends UiBinder<Column, BinaryFieldWidget> {
}
}
class OnChangeFileUpload extends FileUpload {
private Form form;
public OnChangeFileUpload(Form form) {
super();
this.form = form;
sinkEvents(Event.ONCHANGE);
}
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (DOM.eventGetType(event) == Event.ONCHANGE) {
//Window.alert("BEFORE SUBMIT");
form.submit();
}
}
}